import os
import sys
import re
import math
from pathlib import Path
from PIL import Image
import pygame
from moviepy import ImageSequenceClip


# -------------------------- 配置参数（核心调整：减慢切换速度） --------------------------
IMAGE_FOLDER = r"../add_text/pomeranian_visual_reports_final"
OUTPUT_VIDEO_PATH = r"../add_text/photo_book_animation_VERTICAL.mp4"
WINDOW_WIDTH, WINDOW_HEIGHT = 768, 1024  # 竖版尺寸不变
# 1. 核心调整：延长每页停留时间（从1.2秒→2.0秒，观看更充分）
STAY_DURATION = 2.0
# 2. 核心调整：减慢翻页动画（从0.4秒→0.8秒，翻页更平缓）
FLIP_DURATION = 0.8
FPS = 30                  # 帧率不变，确保流畅度
MAX_TOTAL_DURATION = 180.0 # 延长总时长限制（适配更长的停留+翻页时间）
SUPPORTED_FORMATS = (".png", ".jpg", ".jpeg", ".bmp")
BACKGROUND_COLOR = (255, 255, 255)
PAGE_TIP_COLOR = (50, 50, 50)
# -------------------------------------------------------------------------------------------


def natural_sort_key(s):
    """自然排序函数"""
    filename = os.path.splitext(os.path.basename(s))[0]
    parts = re.split(r'(\d+)', filename)
    return [int(part) if part.isdigit() else part.lower() for part in parts]


def load_images(folder_path):
    """加载图片"""
    folder = Path(folder_path).resolve()
    if not folder.exists():
        print(f"❌ 图片文件夹不存在：{folder}")
        sys.exit(1)

    image_paths = sorted(
        [f for f in folder.glob("*") if f.suffix.lower() in SUPPORTED_FORMATS],
        key=natural_sort_key
    )

    if not image_paths or len(image_paths) < 2:
        print(f"❌ 至少需要2张图片，当前找到{len(image_paths)}张")
        sys.exit(1)

    images = []
    for img_path in image_paths:
        try:
            with Image.open(img_path).convert("RGB") as pil_img:
                target_width = WINDOW_WIDTH
                target_height = int(pil_img.height * (target_width / pil_img.width))
                if target_height > WINDOW_HEIGHT:
                    target_height = WINDOW_HEIGHT
                    target_width = int(pil_img.width * (target_height / pil_img.height))
                pil_img = pil_img.resize((target_width, target_height), Image.Resampling.LANCZOS)
                bg = Image.new("RGB", (WINDOW_WIDTH, WINDOW_HEIGHT), BACKGROUND_COLOR)
                x = (WINDOW_WIDTH - target_width) // 2
                y = (WINDOW_HEIGHT - target_height) // 2
                bg.paste(pil_img, (x, y))
                pygame_img = pygame.image.fromstring(bg.tobytes(), bg.size, "RGB")
                images.append(pygame_img)
            print(f"✅ 加载成功：{img_path.name}（缩放后：{target_width}x{target_height}）")
        except Exception as e:
            print(f"⚠️  跳过：{img_path.name} → {str(e)[:30]}")

    print(f"\n📊 加载完成 → {len(images)}张图片（竖版 768×1024 居中显示）")
    return images


def draw_book_page(screen, current_img, next_img, progress, current_page_num, total_pages):
    """绘制翻页效果（不变，仅速度由参数控制）"""
    screen.fill(BACKGROUND_COLOR)
    total_width, total_height = WINDOW_WIDTH, WINDOW_HEIGHT

    if next_img:
        screen.blit(next_img, (0, 0))

    unflipped_height = total_height - int(total_height * progress)
    if unflipped_height > 0:
        top_part_rect = pygame.Rect(0, 0, total_width, unflipped_height)
        top_surf = current_img.subsurface(top_part_rect).copy()
        screen.blit(top_surf, (0, 0))

    flip_height = total_height - unflipped_height
    if flip_height > 0:
        flip_source_rect = pygame.Rect(0, unflipped_height, total_width, flip_height)
        flip_surface_orig = current_img.subsurface(flip_source_rect).copy()
        angle = 180 * progress
        scale_factor = 1.0 - 0.3 * math.sin(progress * math.pi)
        transformed_flip = pygame.transform.rotozoom(flip_surface_orig, angle, scale_factor)
        x_shift = int(total_width * 0.08 * math.sin(progress * math.pi))
        y_draw = unflipped_height - transformed_flip.get_height() // 2
        screen.blit(transformed_flip, (x_shift, y_draw))

        shadow_height = int(total_height * 0.15 * math.sin(progress * math.pi))
        if shadow_height > 0:
            shadow_surf = pygame.Surface((total_width, shadow_height), pygame.SRCALPHA)
            for y in range(shadow_height):
                alpha = int(100 * (1 - y/shadow_height) * math.sin(progress * math.pi))
                pygame.draw.line(shadow_surf, (0, 0, 0, alpha), (0, y), (total_width, y), 1)
            screen.blit(shadow_surf, (0, unflipped_height - shadow_height))

    try:
        font = pygame.font.SysFont("Arial", 24, bold=True)
        text = font.render(f"第{current_page_num}/{total_pages}页", True, PAGE_TIP_COLOR)
        screen.blit(text, (total_width - text.get_width() - 20, total_height - text.get_height() - 20))
    except:
        pass


def capture_frame(screen):
    """捕获帧"""
    frame = pygame.surfarray.array3d(screen).copy()
    return frame.swapaxes(0, 1)


def generate_book_video(images):
    """生成视频（参数引用调整后的速度配置，逻辑不变）"""
    pygame.init()
    screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    pygame.display.set_caption("生成竖版翻页视频...")

    total_pages = len(images)
    all_frames = []
    total_time = 0.0
    # 翻页帧数和停留帧数会自动随 FLIP_DURATION/STAY_DURATION 增加而变多，实现减速
    num_flip_frames = int(FLIP_DURATION * FPS)
    num_stay_frames = int(STAY_DURATION * FPS)

    print(f"\n🎬 开始生成竖版视频（已减慢速度）→ 输出：{Path(OUTPUT_VIDEO_PATH).resolve()}")
    print(f"⏱️  配置：每页停留{STAY_DURATION}秒 | 翻页动画{FLIP_DURATION}秒")

    try:
        for i in range(total_pages):
            current_img = images[i]
            next_img = images[i+1] if i < total_pages - 1 else None

            # 停留帧（因 STAY_DURATION 延长，帧数增加，停留更久）
            for _ in range(num_stay_frames):
                draw_book_page(screen, current_img, next_img, 0.0, i+1, total_pages)
                all_frames.append(capture_frame(screen))
            total_time += STAY_DURATION

            # 翻页帧（因 FLIP_DURATION 延长，帧数增加，翻页更慢）
            if i < total_pages - 1:
                for j in range(num_flip_frames):
                    progress = (j + 1) / num_flip_frames
                    draw_book_page(screen, current_img, next_img, progress, i+1, total_pages)
                    all_frames.append(capture_frame(screen))
                total_time += FLIP_DURATION

            if total_time > MAX_TOTAL_DURATION:
                print(f"⚠️  超出最大时长 {MAX_TOTAL_DURATION} 秒，停止生成")
                break

            print(f"进度：{i+1}/{total_pages}页 | 已捕获 {len(all_frames)} 帧 | 累计时长：{total_time:.1f}秒")

    except Exception as e:
        print(f"❌ 生成失败：{e}")
        pygame.quit()
        sys.exit(1)

    if all_frames:
        print("\n💾 正在合成竖版视频...")
        try:
            clip = ImageSequenceClip(all_frames, fps=FPS)
            clip.write_videofile(
                OUTPUT_VIDEO_PATH,
                codec="libx264",
                audio=False,
                fps=FPS,
                bitrate="6000k",
                logger=None
            )

            if os.path.getsize(OUTPUT_VIDEO_PATH) > 1024*1024:
                print(f"\n🎉 竖版视频生成成功（速度已减慢）！")
                print(f"路径：{Path(OUTPUT_VIDEO_PATH).resolve()}")
                print(f"规格：{WINDOW_WIDTH}×{WINDOW_HEIGHT} | 大小：{os.path.getsize(OUTPUT_VIDEO_PATH)//1024//1024} MB | 时长：{total_time:.1f}秒")
            else:
                print("❌ 视频文件异常（过小）")
        except Exception as e:
            print(f"❌ 保存失败：{e}")
    else:
        print("❌ 无有效帧可合成")

    pygame.quit()


if __name__ == "__main__":
    Path(OUTPUT_VIDEO_PATH).parent.mkdir(parents=True, exist_ok=True)
    book_images = load_images(IMAGE_FOLDER)
    generate_book_video(book_images)